module bias_mul #(
    parameter int unsigned A_BIT = 8,
    parameter int unsigned B_BIT = 16,
    parameter int unsigned M_BIT = 24
) (
    input  logic                    clk,
    input  logic                    rst_n,
    input  logic                    en,
    input  logic signed [B_BIT-1:0] in_data,
    input  logic signed [B_BIT-1:0] bias,
    input  logic        [M_BIT-1:0] mult,
    output logic        [A_BIT-1:0] out_data
);

    localparam int unsigned MULT_BIT = B_BIT + M_BIT + 1;
    localparam int unsigned MAXOUT = (1 << A_BIT) - 1;

    logic        [         A_BIT-1:0] out_data_r;

    // Combinational logic for computation
    logic signed [         B_BIT-1:0] biased;
    logic signed [      MULT_BIT-1:0] mult_result;
    logic signed [MULT_BIT-B_BIT-1:0] shifted;
    logic        [         A_BIT-1:0] activated;

    always_comb begin
        // Add bias
        biased      = in_data + bias;

        // Multiply
        mult_result = biased * $signed({1'b0, mult});

        // Right shift with rounding
        shifted     = right_shift_with_rounding(mult_result, B_BIT);

        // ReLU activation with saturation
        if (shifted > 0) begin
            if (shifted < MAXOUT) begin
                activated = shifted[A_BIT-1:0];
            end else begin
                activated = MAXOUT[A_BIT-1:0];
            end
        end else begin
            activated = '0;
        end
    end

    // Register output (1 cycle delay)
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            out_data_r <= '0;
        end else if (en) begin
            out_data_r <= activated;
        end
    end

    assign out_data = out_data_r;

    // Right shift with rounding function
    function automatic logic signed [MULT_BIT-B_BIT-1:0] right_shift_with_rounding(input logic signed [MULT_BIT-1:0] x,
                                                                                   input int bits);
        logic signed [MULT_BIT-1:0] x1;
        logic                       is_even;
        logic signed [MULT_BIT-1:0] x_even;
        logic signed [MULT_BIT-1:0] x_odd;
        logic signed [MULT_BIT-1:0] result;

        if (bits == 0) begin
            return x[MULT_BIT-B_BIT-1:0];
        end

        x1      = x >>> (bits - 1);
        is_even = (x1[0] == 1'b0);
        x_even  = x1 >>> 1;
        x_odd   = (x1 + 1) >>> 1;
        result  = is_even ? x_even : x_odd;

        return result[MULT_BIT-B_BIT-1:0];
    endfunction

endmodule
